﻿//INSTANT C# NOTE: Formerly VB project-level imports:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
using System.Linq;
using System.Xml.Linq;

using Microsoft.IdentityModel.Protocols.WSFederation.Metadata;
using Microsoft.IdentityModel.SecurityTokenService;
using System.IdentityModel.Tokens;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Xml;
using Microsoft.IdentityModel.Protocols.WSIdentity;

namespace STSFederationMetadataEditor
{
	public class MetadataGenerator
	{
		// Methods
		public MetadataGenerator(ContactPerson contact, Organization organization, string issuerUri, string serviceName, System.Collections.Specialized.StringCollection activeEndpoints, System.Collections.Specialized.StringCollection passiveEndpoints, CustomDisplayClaimCollection claims, X509Certificate2 serviceCert, bool sign)
		{
			this.contact = contact;
			this.organization = organization;
			this.issuerUri = issuerUri;
			this.serviceName = serviceName;
			this.activeEndpoints = activeEndpoints;
			this.passiveEndpoints = passiveEndpoints;
			this.claims = claims;
			this.serviceCert = serviceCert;
			this.sign = sign;
		}

		public MetadataGenerator(string issuerUri, string serviceName, System.Collections.Specialized.StringCollection activeEndpoints, System.Collections.Specialized.StringCollection passiveEndpoints, CustomDisplayClaimCollection claims, X509Certificate2 serviceCert, bool sign)
		{
			this.issuerUri = issuerUri;
			this.serviceName = serviceName;
			this.activeEndpoints = activeEndpoints;
			this.passiveEndpoints = passiveEndpoints;
			this.claims = claims;
			this.serviceCert = serviceCert;
			this.sign = sign;
		}

		private string CreateFederationMetadataAsString(EntityDescriptor entity)
		{
			MetadataSerializer serializer = new MetadataSerializer();
			MemoryStream stream = new MemoryStream();
			serializer.WriteMetadata(stream, entity);
			stream.Seek(0, SeekOrigin.Begin);
			return Encoding.UTF8.GetString(stream.ToArray());
		}

		public void GenerateAsFile(string fileName)
		{
			string contents = this.GenerateCore();
			File.WriteAllText(fileName, contents);
		}

		public string GenerateAsString()
		{
			return this.GenerateCore();
		}

		private string GenerateCore()
		{
			SecurityTokenServiceDescriptor tokenServiceDescriptor = this.GetTokenServiceDescriptor();
			EntityId entityId = new EntityId(this.issuerUri);
			EntityDescriptor entity = new EntityDescriptor(entityId);
			if (this.sign)
			{
				entity.SigningCredentials = new X509SigningCredentials(this.serviceCert);
			}

			if (this.contact != null)
			{
				entity.Contacts.Add(this.contact);
				entity.Organization = this.organization;
			}

			entity.RoleDescriptors.Add(tokenServiceDescriptor);
			return this.CreateFederationMetadataAsString(entity);
		}

		private KeyDescriptor GetSigningKeyDescriptor(X509Certificate2 cert)
		{
			X509RawDataKeyIdentifierClause clause = (new X509SecurityToken(cert)).CreateKeyIdentifierClause<X509RawDataKeyIdentifierClause>();
			KeyDescriptor descriptor = new KeyDescriptor(new SecurityKeyIdentifier(new SecurityKeyIdentifierClause[] {clause}));
			descriptor.Use = KeyType.Signing;
			return descriptor;
		}

		private SecurityTokenServiceDescriptor GetTokenServiceDescriptor()
		{
			Action<EndpointAddress> action = null;
			SecurityTokenServiceDescriptor tokenService = new SecurityTokenServiceDescriptor();
			tokenService.ServiceDescription = this.serviceName;
            tokenService.Keys.Add(this.GetSigningKeyDescriptor(this.serviceCert));
			tokenService.ProtocolsSupported.Add(new Uri("http://docs.oasis-open.org/wsfed/federation/200706"));
			tokenService.TokenTypesOffered.Add(new Uri("urn:oasis:names:tc:SAML:1.0:assertion"));
			foreach (var claim in claims)
			{
				tokenService.ClaimTypesOffered.Add(claim.GetDisplayClaim());
			}
//INSTANT C# NOTE: Commented this declaration since looping variables in 'foreach' loops are declared in the 'foreach' header in C#:
//			string uri = null;
			foreach (string uri in this.activeEndpoints)
			{
				MetadataSet set = new MetadataSet();
				MetadataReference metadata = new MetadataReference(new EndpointAddress(string.Format("{0}/mex", uri)), AddressingVersion.WSAddressing10);
				MetadataSection item = new MetadataSection(MetadataSection.MetadataExchangeDialect, null, metadata);
				set.MetadataSections.Add(item);
				StringBuilder sb = new StringBuilder();
				StringWriter w = new StringWriter(sb);
				XmlTextWriter writer = new XmlTextWriter(w);
				set.WriteTo(writer);
				writer.Flush();
				w.Flush();
				StringReader input = new StringReader(sb.ToString());
				XmlTextReader reader = new XmlTextReader(input);
				XmlDictionaryReader metadataReader = XmlDictionaryReader.CreateDictionaryReader(reader);
				EndpointAddress address = new EndpointAddress(new Uri(uri), null, null, metadataReader, null);
				tokenService.SecurityTokenServiceEndpoints.Add(address);
			}
			bool addPassiveEndpointsAsActive = tokenService.SecurityTokenServiceEndpoints.Count == 0;
			foreach (var item in this.passiveEndpoints)
			{
				EndpointAddress endpoint = new EndpointAddress(item);
				tokenService.PassiveRequestorEndpoints.Add(endpoint);
				if (addPassiveEndpointsAsActive)
				{
					tokenService.SecurityTokenServiceEndpoints.Add(endpoint);
				}
			}
			return tokenService;
		}


		// Fields
		private System.Collections.Specialized.StringCollection activeEndpoints;
		private CustomDisplayClaimCollection claims;
		private ContactPerson contact;
		private string issuerUri;
		private Organization organization;
		private System.Collections.Specialized.StringCollection passiveEndpoints;
		private X509Certificate2 serviceCert;
		private string serviceName;
		private bool sign;
	}
}